Motivācija: Žūrnālfaili faktiski ir vislabākais informācijas avots par sistēmu darbību. Žurnālfailu apstrāde ir viena no vērtīgākajām prasmēm IS pārvaldībā. Un tad vēl tas NIS2... ;-) Varam ķert kļūdas un varam noteikt, vai kāds nesnaikstās (vai drizāk - cik daudz snaikstās) gar mūsu “durvīm” u.tml.

Owrt rūteri jau labu laiku ir manu personīgo tīklu pamatā. Tam nesen pievienojās OMV(openmediavault) serveri. Tā nu radās doma tiem likt sadarboties žurnalēšanas apstrādē.

Nepieciešamās priekšzināšanas: Linux, OWRT, OMV, Docker-Compose, Tīklošana...

Pamatdideja OWRT žurnalēšanai: OWRT -> Syslogd -> Grafana-Alloy -> Loki -> Grafana

1. Izveidojam docker compose konfigurāciju priekš rsyslogd:

Sākumā sagatavojam rsyslog konteineri. Iekš openmediavault omvextras tas izskatās sekojoši: Dockerfile:

version: "3.8"  # Specify a version (recommended)

networks:
  loki:

services:
  rsyslogd:
#    image: rsyslogd-image
    image: rsyslog/syslog_appliance_alpine:latest
    ports:
      # Expose the syslog port (UDP) - or 514/tcp if needed
      - "514:514/udp"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TIME_ZONE}
    volumes:
      # Named volume for logs
      - ${RSYSLOG_CONFIG_DIR}:/etc
      - ${OPENWRT_LOGS_DIR}:/var/log

un atbilsošais env faila saturs:

RSYSLOG_CONFIG_DIR=/srv/jūsu_openmediavault_diska_identifikators_vai_share/grafana/rsyslog_config
OPENWRT_LOGS_DIR=/srv/jūsu_openmediavault_diska_identifikators_vai_share/grafana/openwrt_logs
PUID=1005
PGID=1006
TIME_ZONE=Europe/Riga

Ievēro: OMV (openmediavault) gadījumā un vispār dokera konteineru gadījumā japārliecinās, ka dokera konteineru lietotājiem ir atbilstošās saimniekdatora piesaistīto mapju un failu rakstīšanas tiesības. Skat. OMV

2. Rsyslog konfigurācija iekš rsyslog.conf:

Piesaistītajā datņu mapē (RSYSLOG_CONFIG_DIR) izveidojam rsyslog.conf:

# rsyslog.conf (Main configuration file - /etc/rsyslog.conf inside container)

module(load="imudp")  # For UDP syslog reception (or imtcp for TCP)
input(type="imudp" port="514")  # Listen on the default syslog port (514)

# Include configuration files from the rsyslog.d directory
include(file="/etc/rsyslog.d/*.conf")

# $AllowedSender - specifies which remote systems are allowed to send syslog messages to rsyslogd
# Šeit ieraksta, vai nu atļaujos adrešu apgabalus, vai konkrētas adreses
$AllowedSender UDP, 192.168.1.0/24, [::1]/128, kaads.mans.server, *.mans.domens 
# Izslēdzu jo rsyslog IP addresi VPN gadījumā uzrāda, kā nākošu no cita/VPN adrešu apgabala / apkštīkla.

#Custom template to generate the log filename dynamically based on the client's IP address.
#$template RemoteLogs, "/var/log/servers/%FROMHOST-IP%/%PROGRAMNAME%.log"
$template RemoteLogs,"/var/log/servers/%HOSTNAME%/%PROGRAMNAME%.log"
*.* ?RemoteLogs
& ~

AllowSender attiecīgi samainam adresāciju atbilstoši jūsu OpenWRT un/vai tīkla adresācijai. Žurnālfailu atrašanās (/var/log/...) konteneru iekšpusē.

Ķerambedre: Ja ceram dabūt UDP logus no VPN tīkla, tad atkarībā no konfigurācijas izcelsmes IP adrese var nebūt gaidītā. Lai gan variet sasniegt datorus citā VPN tīkla adrešu apgabalā pēc tam atbilstošām adresēm, tad izejošā adrese var būt cita, ko jāskatās VPN konfigurācijā.

3. syslog apakškonfigurācijas iekš /etc/rsyslog.d:

Ieriekšējā sadaļā konfigurācijā ir norāde, ka var iekļaut citas konfigurācijas, kas var būt noderīgi, dažādu žurnālfailu saņemšanai un pirmasptrādei. Šo pašu konfigurāciju faktiski var izmantot dažādu žurnālfailu saņemšanai. Iesākumā gan tas nav vajadzīgs pietiek ar galveno iepriekšējā sadaļā esošo rsyslog.conf

Šīnī brīdī palaižot konteneri un atbilstoši nokonfigurējot ārējos log piegādātājus (piemēram kādu OWRT rūteri, vai tml.), jau varam (un vajag... ;-) ) šo sadaļu notestēt un pārliecināties, ka log dati tiek piegādāti un parādās atbilstošajā mapēs. OWRT rūtera konfigurācijā atiecīgi norādam, ka žurnalēšana notiks nosūtot uz mūsu OMV servera.

4. Konfigurējam Grafana un saistītos doker konteinerus: Grafanna-Alloy (Promtail -> Grafana Agent) logu lasīšanai un nosūtīšanai uz Loki

Pēc netā esošajās info uzdūros receptēm, kur nākošajā logu apstrādes solī tiek izmantots Promtail, bet palasot dokumentāciju, izrādādās promtail ir depreciated. Skatamies aizvietotāju Grafana-Agent, bet arī tas izrādās ir depreciated, abiem gan vēl ir kādu gadu(s) uz priekšu uzturēšanas termiņš. Attiecīgi nonācām līdz pēdējam, kas ir Grafana-Alloy. Šeit gan sastopam tādu lietu, ko ir vērts pastudēt, lai ietu tālāk - LogQL (log query language)

Loki OMV vidē izmantojot ENV failu nepieciešama sekojoša rinda: -config.expand-env=true Tad Grafana + Loki + Alloy docker compose (yml) datnes sadaļa, kas darbojas OMV izskatās šādi:

version: "3.8"  # Specify a version (recommended)

networks:
  loki:

services:

  alloy:
    image: grafana/alloy:latest
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
    ports:
      - 12345:12345
    volumes:
      - ${GRAFANA_AGENT_CONFIG_DIR}:/etc/alloy
      - ${OPENWRT_LOGS_DIR}:/tmp/app-logs/
    command: run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloy
    depends_on:
      - loki
    networks:
      - loki
      
  loki:
    image: grafana/loki:main
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
    ports:
      - 3100:3100
    volumes:
      - ${LOKI_CONFIG_DIR}:/etc/loki
    command: 
      -config.file=/etc/loki/local-config.yaml
      -config.expand-env=true
    networks:
      - loki

  grafana:
    image: grafana/grafana:latest
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
    ports:
      - "3030:3000"
    networks:
      - loki
    depends_on: # Ensure Loki is running before Grafana
      - loki

un atbilstošais .env:

OPENWRT_LOGS_DIR=/srv/jūsu_openmediavault_diska_identifikators/grafana/openwrt_logs
GRAFANA_AGENT_CONFIG_DIR=/srv/jūsu_openmediavault_diska_identifikators/grafana/grafana_alloy_conf
LOKI_CONFIG_DIR=/srv/jūsu_openmediavault_diska_identifikators/grafana/loki_config
PUID=1005
PGID=1006

Pirms laižam šo gaisā, jāsakonfigurē Graffana-Alloy un Loki. OMV atbilstošajās izdalīto datņu mapēs nepieciešamas sekojošas datnes (skat docker comose yaml datni augstāk):

5. Loki Configuration (local-config.yaml):

# This is a complete configuration to deploy Loki backed by the filesystem.
# The index will be shipped to the storage via tsdb-shipper.

# Šo varam iesākumā vienkārības labad atslēgt,
# sakonfigurēsim vēlāk, kad šis strādās.
auth_enabled: false  

limits_config:
  allow_structured_metadata: true
  volume_enabled: true

server:
  http_listen_port: 3100

common:
  ring:
    instance_addr: 0.0.0.0
    kvstore:
      store: inmemory
  replication_factor: 1
  path_prefix: /tmp/loki

schema_config:
  configs:
  - from: 2020-05-15
    store: tsdb
    object_store: filesystem
    schema: v13
    index:
      prefix: index_
      period: 24h

storage_config:
  tsdb_shipper:
    active_index_directory: /tmp/loki/index
    cache_location: /tmp/loki/index_cache
  filesystem:
    directory: /tmp/loki/chunks

pattern_ingester:
  enabled: true

Piezīme par auth_enabled: false: Atkarībā no drošības prasībām un tehniskā risinājuma šo var arī atstāt. Piemēram: nodalītā virtuālajā lokalājā tīklā, kas nav nekam citam paredzēts. Bet jebkurā gadījumā tas uz paša atbildību un zināšanām... ;-)

6. Grafana-Alloy configuration (config.alloy)

local.file_match "applogs" {
  path_targets = [{"__path__" = "/tmp/app-logs/servers/*/*.log"}]
  sync_period = "5s"
}

loki.write "local_loki" {
  endpoint {
    url = "http://loki:3100/loki/api/v1/push"
  }
}

loki.relabel "extract_labels" {
  forward_to = [loki.process.add_new_label.receiver]
  rule {
    source_labels = ["filename"]
    target_label = "server_name"
    regex = "/tmp/app-logs/servers/(?P<server_name>.*)/.*\\.log"
    replacement = "$1"
    action = "replace"
  }
  rule {
    source_labels = ["filename"]
    target_label = "app_name"
    regex = "/tmp/app-logs/servers/.+?/(?P<app_name>.*)\\.log"
    replacement = "$1"
    action = "replace"
  }
}

loki.source.file "local_files" {
  targets     = local.file_match.applogs.targets
  forward_to = [loki.relabel.extract_labels.receiver]
}

loki.process "add_new_label" {
  stage.logfmt {
    mapping = {
      "extracted_level" = "level",
      "extracted_logger" = "logger",
    }
  }

  stage.labels {
    values = {
      "level" = "extracted_level",
      "logger" = "extracted_logger",
    }
  }
  forward_to = [loki.write.local_loki.receiver]
}

Ja visu esam pareizi salikuši, tad kontenerim vajadzētu veiksmīgi pārbaudīties ar check un palaisties ar up

Atkarībā no konteineru pārvaldības vēlmēm abus yaml un env failus var salikt vienā. Pēc palaišanas OMV gadījumā jau redzēsim vai visi servisi ir pacēlušies: 2025-03-03_22-54-39.pngJa būs kāda problēma un nebūs zaļais Up, ieselektējam konteineri un izmantojam tā žurnalēšnas info (logs and follow logs): 2025-03-03_22-57-10.png Ja viss ir veiksmīgi palaidies, tad varam pārbaudīt konteineru iekšējo konfigurāciju darbību.

Vispirms varam pārbaudīt Grafana-Alloy web saskarnē vai log faili lasās, transformējas un/vai transportējas: 2025-03-01_23-18-41.png Pēc tam pašā Grafanā vajadzētu veiksmīgi pievienoties Logi datu avotam: 2025-03-01_23-20-01.png2025-03-03_22-44-09.png Tagad iespējams, ka labs laiks kafijas pauzei. Atkarībā no kādus žurnalēšanas info saņemat un cik intensīvi darbojas Jūsu rūteris, iespējams, ka kādu brīdi jāpagaida, lai ienāktos kādi žurnalēšanas dati. Jebkurā gadījumā ar vairāk logiem varētu būt interesantāk strādāt: 2025-03-03_23-37-40.png Tālāk jau nedaudz cita tēma, kā darboties ar Grafana, bet pirmajos soļos varētu dabūt ko šādu: 2025-03-03_23-43-21.png 2025-03-01_23-31-49.pngŠeit tiek atfiltrētas žurnalētās kļūdas un redzama to dinamika. Atliek tikai rakt dziļāk...

References: * https://blog.raphaelpiccolo.com/fr/post/show/849 * https://www.youtube.com/watch?v=xtEppndO7F8&t=43s * https://github.com/grafana/loki-fundamentals/tree/intro-to-ingesting * https://killercoda.com/grafana-labs/course/loki/intro-to-ingest * https://signoz.io/guides/a-regex-in-query-in-grafana/ * https://community.grafana.com/t/grafana-agent-flow-get-label-from-part-of-file-path/111431/3